/**
 * Program to run the location client.
 *
 * @author Timothy Flynn (trflynn@wpi.edu)
 */
#include <iostream>
#include <queue>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
using std::queue;
using std::cout;
using std::endl;

#include "common.h"
#include "Packet.h"
#include "Frame.h"
#include "DataLinkLayer.h"
#include "PhysicalLayer.h"

// Queues to store frames/packets for inter-level comm
queue<Packet *> sendPktQ, recvPktQ;
queue<Frame *> sendFrameQ, recvFrameQ;

// Semaphores to protect access to queues
pthread_mutex_t sendPktM, recvPktM;
pthread_mutex_t sendFrameM, recvFrameM;

int main(int argc, char** argv) {
	char *servName;
	FILE *txtFile = NULL;
	char *currCmd, *msgBuff, c;
	Packet *p,*p2;

	// Check cmd line args
	if(argc < 2 || argc > 3) {
		printf("Usage: %s serverName [textFile]\n", argv[0]);
		return 1;
	} else if(argc == 3) {
		txtFile = fopen(argv[2], "r");
	
		// Make sure we could open the file
		if(txtFile == NULL) { 
			printf("Error opening file: %s\n", argv[2]);
			return 1;
		}
	}
	servName = argv[1];

	pthread_mutex_init(&sendPktM, NULL);
        pthread_mutex_init(&recvPktM, NULL);
        pthread_mutex_init(&sendFrameM, NULL);
        pthread_mutex_init(&recvFrameM, NULL);

        PhysicalLayer *phys = new PhysicalLayer("localhost", 0.05);
        DataLinkLayer *data = new DataLinkLayer();

	// Launch DL and PL threads
        pthread_t pt, dt;
        pthread_create(&dt, NULL, runDataLinkLayer, data);
        pthread_create(&pt, NULL, runPhysicalLayer, phys);

	// Run until we receive quit EOF message
	int i, running = 1;

	// Run util we receive quit message
	while(running) {
		currCmd = (char *)malloc(MAX_PACKET_SZ);
		msgBuff = (char *)malloc(MAX_PACKET_SZ);

		// Get the message from cmd line or text file
		if(txtFile == NULL) {
			i = 0;
			printf("Please enter command: ");

			while(((c=getchar()) != '\n') && (c != EOF)) {
				currCmd[i++] = c;
			}
			currCmd[i++] = '\0';
		} else {
			if(fgets(currCmd, MAX_PACKET_SZ, txtFile) == NULL) {
				break;
			}
			currCmd[strlen(currCmd) - 1] = '\0';

			i = strlen(currCmd) + 1;
			cout << "Read from file: " << currCmd << endl;
		}

		// Check for quit
		if(strcasecmp("quit", currCmd) == 0) {
			cout << "Exiting" << endl;
			break;
		}

		p = (Packet *)malloc(sizeof(Packet));
		p->end = true;
		p->seq = 0;
		p->length = strlen(currCmd);
		p->data = (char *)malloc((p->length+1) * sizeof(char));
		memcpy(p->data, currCmd, p->length);
		p->data[p->length] = '\0';
		sendPktQ.push(p);

		printf("Client received: ");
		int keepReading = 1;
		while(keepReading) {
			int readAnything = 0;

			while(!readAnything) {
				pthread_mutex_lock(&recvPktM);
				if(!recvPktQ.empty()) {
					p2 = recvPktQ.front();
					recvPktQ.pop();
					readAnything = 1;
				}
				pthread_mutex_unlock(&recvPktM);
			}

			// Check if this was the DLE ETX message
			if(p2 == NULL || p2->end) {
				keepReading = 0;
			}

			// Print the response
			cout << p2->data << " ";
		}
		cout << endl << endl;

		free(currCmd);
		free(msgBuff);
		free(p); free(p2);
	}

	// Close the files
	if(txtFile != NULL) {
		fclose(txtFile);
	}

	data->printStats();

	return 0;
}
